﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICeFramework.DataAccess.Interfaces;
using ICeFramework.Common.DataLayer;
using System.Data;
using ICeFramework.Common.DataLayer.Interfaces;
using System.Configuration;
using System.Data.SqlClient;
using ICeFramework.Common.Configuration;
using System.Data.Common;
using ICeFramework.DataAccess.DataLayer.Enums;
using ICeFramework.DataAccess.Proxy;

namespace ICeFramework.DataAccess.DataLayer
{
    public abstract class DataAccessService : IDataAccessService
    {
        private string _connectionName = string.Empty;
        private string _remoteConnectionUrl = string.Empty;

        private bool _local = true;
        #region public bool Local
        /// <summary>
        /// Gets the Local of the DataAccessService
        /// </summary>
        /// <value></value>
        public bool Local
        {
            get { return _local; }
        }
        #endregion

        private DALProxy _proxy;
        protected DALProxy Proxy
        {
            get { return _proxy; }
            set { _proxy = value; }
        }

        #region public DataAccessService()
        /// <summary>
        /// Initializes a new instance of the <b>DataAccessService</b> class.
        /// </summary>
        public DataAccessService()
        {
            //_connection = new DbConnection(ConfigurationHelper.GetConnectionString());
        }
        #endregion

        #region public DataAccessService(string connectionStringName)
        /// <summary>
        /// Initializes a new instance of the <b>DataAccessService</b> class.
        /// </summary>
        /// <param name="connectionStringName"></param>
        public DataAccessService(string connectionName)
        {
            _connectionName = connectionName;
        }
        #endregion

        public DataAccessService(Uri remoteConnectionUrl)
        {
            _remoteConnectionUrl = remoteConnectionUrl.ToString();
            _local = false;
        }

        #region IDataAccessService Members

        private IDbConnection _connection;
        #region public IDbConnection Connection
        /// <summary>
        /// Gets/Sets the Connection of the DataAccessService
        /// </summary>
        /// <value></value>
        public IDbConnection Connection
        {
            get 
            {
                if (_connection == null)
                {
                    _connection = new SqlConnection(ConfigurationHelper.GetConnection(_connectionName));
                }
                return _connection; 

            }
            set { _connection = value; }
        }
        #endregion

        public abstract string ParamToken
        {
            get;
        }
        
        public virtual void Fill(DataTable table, EntityFilter filter)
        {
            Fill(table, filter, null, null);
        }

        public virtual void Fill(DataTable table, EntityFilter filter, IDbTransaction transaction)
        {
            Fill(table, filter, null, transaction);
        }

        public virtual void Fill(DataTable table, EntityFilter filter, EntityOrder order)
        {
            Fill(table, filter, order, null);
        }

        public abstract void Fill(DataTable table, EntityFilter filter, EntityOrder order, IDbTransaction transaction);

        public virtual void Fill(DataTable table, EntityFilter filter, int pageIndex, int pageSize, out long totalRowsCount)
        {
            Fill(table, filter, null, pageIndex, pageIndex, out totalRowsCount, null);
        }

        public virtual void Fill(DataTable table, EntityFilter filter, int pageIndex, int pageSize, out long totalRowsCount, IDbTransaction transaction)
        {
            Fill(table, filter, null, pageIndex, pageIndex, out totalRowsCount, transaction);
        }

        public virtual void Fill(DataTable table, EntityFilter filter, EntityOrder order, int pageIndex, int pageSize, out long totalRowsCount)
        {
            Fill(table, filter, order, pageIndex, pageIndex, out totalRowsCount, null);
        }

        public abstract void Fill(DataTable table, EntityFilter filter, EntityOrder order, int pageIndex, int pageSize, out long totalRowsCount, IDbTransaction transaction);

        public virtual void Fill(DataTable table, StoredProcedureDefinition spDefinition)
        {
            Fill(table, spDefinition, null, null);
        }

        public virtual void Fill(DataTable table, StoredProcedureDefinition spDefinition, IDbTransaction transaction)
        {
            Fill(table, spDefinition, null, transaction);
        }

        public virtual void Fill(DataTable table, StoredProcedureDefinition spDefinition, EntityOrder order)
        {
            Fill(table, spDefinition, order, null);
        }

        public abstract void Fill(DataTable table, StoredProcedureDefinition spDefinition, EntityOrder order, IDbTransaction transaction);

        public virtual int Count(DataTable table)
        {
            return Count(table, null);
        }

        public abstract int Count(DataTable table, EntityFilter filter);

        public void Update(DataTable table, List<EntityColumn> columns)
        {
            Update(table, columns, null);
        }

        public void Update(DataRow row, List<EntityColumn> columns)
        {
            Update(row, columns, null);
        }

        public abstract void Update(DataTable table, List<EntityColumn> columns, IDbTransaction transaction);
        public abstract void Update(DataRow row, List<EntityColumn> columns, IDbTransaction transaction);

        #endregion

        internal DataParameterCollection GetCommandParameters(List<EntityColumn> columns, DataRow row, DBCommandType commandType)
        {
            DataParameterCollection collection = new DataParameterCollection();
            foreach (EntityColumn col in columns)
            {
                switch (commandType)
                {
                    case DBCommandType.Update:
                        //if (!col.IsInPrimaryKeys)

                        if (col.IsInPrimaryKeys)
                        {
                            collection.Add(new DataParameter("o" + col.Name, row[col.Name], col.DbType, ParameterDirection.Input, DataRowVersion.Original, col.Name, col.AllowNull));
                        }
                        else if (!col.IsReadOnly)
                        {
                            collection.Add(new DataParameter("c" + col.Name, row[col.Name], col.DbType, ParameterDirection.Input, DataRowVersion.Current, col.Name, col.AllowNull));
                        }
                        //if (!col.IsInPrimaryKeys && !col.IsReadOnly)
                        //{
                        //    collection.Add(new DataParameter("c" + col.Name, row[col.Name], col.DbType, ParameterDirection.Input, DataRowVersion.Current, col.Name, col.AllowNull));
                        //    if (row[col.Name, DataRowVersion.Original] == row[col.Name, DataRowVersion.Current])
                        //    {
                        //        collection.Add(new DataParameter("o" + col.Name, row[col.Name], col.DbType, ParameterDirection.Input, DataRowVersion.Original, col.Name, col.AllowNull));
                        //    }
                        //}
                        //else if (!col.IsReadOnly)
                        //{
                        //    collection.Add(new DataParameter("o" + col.Name, row[col.Name], col.DbType, ParameterDirection.Input, DataRowVersion.Original, col.Name, col.AllowNull));
                        //}
                        break;
                    case DBCommandType.Delete:
                        //if (row[col.Name, DataRowVersion.Original] == row[col.Name, DataRowVersion.Current])
                        {
                            collection.Add(new DataParameter(col.Name, row[col.Name, DataRowVersion.Original], col.DbType, ParameterDirection.Input, DataRowVersion.Current, col.Name, col.AllowNull));
                        }
                        break;
                    case DBCommandType.Insert:
                        if (!col.IsInPrimaryKeys && !col.IsReadOnly && row[col.Name] != DBNull.Value)
                        {
                            collection.Add(new DataParameter(col.Name, row[col.Name], col.DbType, ParameterDirection.Input, DataRowVersion.Current, col.Name, col.AllowNull));
                        }
                        break;
                }
            }

            return collection;
        }
    }
}
